"""
pql - PACP Query Language
eg. a query like this "3MGO, RFC, <3JOM, -RFJ" means,

Inspections that has 3 MGOs, at least 1 RFC, less than 3 JOMs and no RFJ.
"""
from pacp.model import run_flds, detail_flds
import re
#p = """
#([>,<,\-,>=,<=]{0,1})   #>=, logical operator
#([0-9]{0,1})           #3, count
#([a-zA-Z,?]           #M, First code 
#[a-zA-Z,?]{0,1}      #G, Second code
#[a-zA-Z,?]{0,1}
#[a-zA-Z,?]{0,1})      #O, thrid code
## (@.*){0,10}       #@(5,6) to be expanded later
#"""
#
#p2 = """
#(^[a-zA-Z].*)   #field namee
#=               #seperator
#(.*)            #value
#"""
#pattern = re.compile(p, re.VERBOSE)
#pattern2 = re.compile(p2, re.VERBOSE)
#
#def _parser(pql):
#    k = ['op', 'ct', 'c']
#    return dict(zip(k, pattern.search(pql).groups()))
#
#
#
#def parsePql(pqls):
#    pqls = pqls.replace(' ','')
#    pqls = pqls.replace('?', '%')
#    
#    results = []
#    for pql in pqls.split(','):
#        try:
#            result = dict(zip(['k','v'],pattern2.search(pql).groups()))
#        except:
#            result = _parser(pql)
#        
#        results.append(result)
#    return results
#        
#
#
#
#p1 = """
#^([a-zA-Z\?]{1,2})(>=|<=|<>)([0-9])           #3, count
#"""
#
#p2 = """
#(^[a-zA-Z0-9]*)=(.*)            #value
#"""
#
def parser1(p, s):
    #interface for parser, take two parameters
    #p-pattern
    #s-the code
    return re.compile(p, re.VERBOSE).search(s).groups()

defect_count_clause = """
            ((select count(*) from Details 
            where
            Details.RunID = Runs.RunID
            and
            Details.ConditionCode like "%s")%s%s)"""



def valid_key(k, rules):
    for rule in rules:
        if rule(k)==False:
            return False
    return True
    
    
inspectionColumn_rules = [
                          lambda k: k.lower() in [x.lower() for x in run_flds]]    
    

def inspectionColumn_parser(o):
    k, v = o[3][0], o[3][2]
    #assuming all field are text,and ignoring the >,< etc.
    if valid_key(k, inspectionColumn_rules):
        return '(Runs."%s" like "%%%s%%")' % (k,v)
    else:
        return None

def defectCode_parser(o):    
    c, op, ct = o[3][0],o[3][1],o[3][2]
    
    return defect_count_clause % (c, op, ct)


    
    
    


class Pql(object):
    
    #this is bad. I should use something much simpler, jsut give a list of valid fields. As long as I can get c, op, ct.
    #I should be able to tell what to do based on the c value.No need for complicated regular expression.
    ruleSets = [
                
                ('inspectionColumn', '^(.*):(>=|=|<=|<>|>|<)(.*)', parser1, [ 'k', 'op', 'v']),
                ('defectCode','^([a-zA-Z\%]{1,4})(>|<|>=|=|<=|<>)([0-9])', parser1, ['c', 'op', 'ct']) 
                ]
    sqlParsers = {
                  'inspectionColumn': inspectionColumn_parser,
                  'defectCode': defectCode_parser
                  }
    

    def _parseExp(self, s):
        # return a list in the format of 
        # 's', 'rule', 'flds',att1, att2, att...
        for rule, pattern, parseFunc, flds in self.ruleSets:
            try:

                result =  parseFunc(pattern, s.strip())
                #don't change the order the list, it is the api
                return  [s, rule, flds, result]
            except:
                result = None

        return  [s, rule, flds, result]

        
    def toSQL(self):
        results = []
        parse_results = []
        for r in self.parse():
            [s, rule, flds, result] = r
            if result:
                if self.sqlParsers[rule](r):
                    results.append(self.sqlParsers[rule](r))
                    parse_results.append({'code': s, 'status': 'OK'})
                else:
                    self.valid = False
                    parse_results.append({'code': s, 'status': 'ERROR'})
            else:
                self.valid = False
                parse_results.append({'code': s, 'status': 'ERROR'})
        if len(results)==0:
            self.SQL = 'select * from Runs'
        else:
            self.SQL = 'select * from Runs where ' + ' AND '.join(results)
        self.results = parse_results
        return  self.SQL
            
            

             
        pass
    
    def parse(self):
        exps = self.statement.split(self.token)
        results = []
        for exp in exps:
            result = self._parseExp(exp.replace('?', '%'))
            results.append(result)
        return results
            

        
    def __init__(self, ss, token = ','):
        #interface
        self.statement = ss.replace('\n', '') #orignial query
        self.token = token  #the token seperate parts
        self.valid = True   #flag, if all code is valid
        self.results = None #reults in list, each code is an item
        self.toSQL()


success = """
mgo=1,
mgo<1,
mgo>1,
mgo>=1,
mgo<=2,
mgo<>1,
m?o=1,
m??>1,
???<1,
field1:=1,
field2:=two,
field3:<=1,
field4:>=text

"""
fail = """
*/-+,
 2RFC, 
 ?go,
 ??o,
 ???,
 >mgo,
 <mgo,
 =mgo,
 -mgo,
 >=mgo,
 <=mgo,
 >3J?M,
  <2T??,
  ?=TOC,
  field2=textvalue,
  without this one,
  mgowls;asd,
  abcd,
  efgh"""

print '*'*50
print 'all these should fail'
p = Pql(fail)    

for x in p.parse():
    print x
    
print '*'*50    
print 'all these should pass'

for x in Pql(success).parse():
    print x
    
print Pql('mgo=0, PIPETECHID:=0086?').toSQL()

